/*##############################################################################
#  <PythonObject.js>
##############################################################################*/

// This makes compiling from Python a little easier :)
False = false
True = true

/*##############################################################################
################################################################################
##  
##                          PythonObject
##
################################################################################
##############################################################################*/
//Defines the top level PythonObject
// Some code stolen from
// http://truecode.blogspot.com/2006/08/object-oriented-super-class-method.html
function PythonObject() {
}
PythonObject.prototype.construct = function(args) {};
// Prettyprint PythonObjects
PythonObject.prototype.toString = function() {
  var s = "{";
  for(var i in this) {
    s += i + " : "
    if(typeof this[i] == "function") {
      s += "function()"
    }
    else if(typeof(this[i]) == "string") {
      s += '"'+ escape(this[i]) + '"';
    }
    else {
      s += this[i]
    }
    s += ",\n"
  }
  return s + "}"
}

PythonObject.extend = function(def) {
  var PythonObjectDef = function() {
    this.__dict__ = {}
    if (arguments.length < 1 || typeof arguments[0] != "object") {
      throw "This object requires a dictionary passed in."
    }
    if (arguments.length < 2) {
      arguments[1] = {"sync":true} // The user didn't pass any options in.
    }
    if (arguments[0] !== PythonObject) {
      // Check if we have a this._PSTJ_FromServer - if we don't, 
      // we need to create this obj on the server
      if(!arguments[0]["_PTJS_FromServer"]) {
        var options = arguments[1]
        if(typeof options != "object" || options == null) options = {"sync":true}
        if(typeof options["sync"] != "boolean") options["sync"] = true
        return PythonObject.RPC(null,arguments[0],options,
                                {"_PTJS_ObjectName":this._PTJS_ObjectName})
      }
      for(var i in arguments[0]) {
          this.__dict__[i] = arguments[0][i];
      }
      // Some compilers may build caching mechanisms. This hook lets us 
      // cache these things.
      if(typeof(this._PTJS_addToCache) == "function") {
        this._PTJS_addToCache(this)
      }
      /* IMPORTANT NOTE: adding to the cache *overwrites* the object that was
      there before. If there are any references to that object, they'll be
      holding on to an *old* copy. So:
      1. Either we don't create a new objet, like above, but "update" the old.
      2. Don't create a new object, just return the existing one?
      */
    }
  };
  var proto = new this(PythonObject);
  var superPythonObject = this.prototype;
  for (var n in def) {
    var item = def[n];                        
    if (item instanceof Function) item.$ = superPythonObject;
    proto[n] = item;
  }
  PythonObjectDef.prototype = proto;

  //Give this new PythonObject the same static methods
  PythonObjectDef.extend = this.extend;
  PythonObjectDef.RPC = this.RPC;
  return PythonObjectDef;
};

/*##############################################################################
##                Remote Procedure Call functions, allowing us to call
##                stuff in PythonObjects. Funky!  
##############################################################################*/
// RPC - generic Remote Procedure Call. Doesn't know about particular objects.
// Useful for calling things like PythonObject.get(id)
PythonObject.RPC = function(method,args,options,kwargs,obj) {
// Options must be a dictionary. Accepted options are:
// cb, ecb, sync


  // Check arguments ///////////////////////////////////////////
  if(typeof kwargs != "object" || kwargs == null) {           //
    kwargs = {}                                               //
  }                                                           //
  if(typeof options == "function") {                          //
    options = {"cb":options}                                  //
  }                                                           //
  //////////////////////////////////////////////////////////////
  kwargs["_PTJS_MethodArgs"] = args;
  kwargs["_PTJS_Method"] = method;
  if(typeof kwargs["_PTJS_ObjectName"] == "undefined") {
    kwargs["_PTJS_ObjectName"] = this.prototype._PTJS_ObjectName;
  }
  var e = new _PTJS_RPC(kwargs,options,obj)
  return e.result
}

/*##############################################################################
################################################################################
##  
##                PythonException - to handle server-side exception
##
################################################################################
##############################################################################*/
function PythonException(kwargs) {
  this.name = "PythonException"
  this.errorcode = kwargs.ErrorCode
  this.message = kwargs.ErrorMessage
  throw Error(this)
}
PythonException.prototype.toString = function() {
  return "Backend error: " + this.errorcode + "\n" + this.message;
}
/*##############################################################################
#  </PythonObject.js>
##############################################################################/*
